
import List::*;

// //@ \subsection{Clocks and Resets}
//@ \index{Clocks@\te{Clocks} (package)|textbf}
//@
//@ The BSV \te{Clocks} library provide features to access and change
//@ the default clock.  Moreover, there are hardware primitives to
//@ generate clocks of various shapes, plus several primitives which
//@ allow the safe crossing of signals and data from one clock domain
//@ to another.
//@

//@ \subsubsection{Clock Generators and Manipulation}
//@
//XXX@  exposeCurrentClock needs to be documented.

//X@
//X@ \index{ClockGenIfc@\te{ClockGenIfc} (interface)|textbf}
//X@ An interface for a module which provides (generates) a clock.
//X@ # 3
// Needed for module BVI, users should not need this
interface ClockGenIfc;
  interface Clock gen_clk;
endinterface

//@
//@ \index{mkAbsoluteClock@\te{mkAbsoluteClock} (module)|textbf}
//@ \te{mkAbsoluteClock} provides a parameterizable clock
//@ generation module, with its first rising edge (start) and period
//@ defined by parameters.
//@ This module is not synthesizable.
//@ # 3
module mkAbsoluteClock #( Integer start,
                          Integer period
                         ) ( Clock );
   (* hide *)
   ClockGenIfc _m <- vMkAbsoluteClock(start,period);
   return _m.gen_clk();
endmodule

import "BVI" ClockGen =
module vMkAbsoluteClock #( Integer start,
                           Integer period
                          ) ( ClockGenIfc );
   let halfPeriod = div( period,  2) ;
   default_clock no_clock;
   parameter v1Width = halfPeriod ;
   parameter v2Width = period - halfPeriod ;
   parameter initDelay  = start;
   parameter initValue = 0 ;
   parameter otherValue = 1 ;
   no_reset;
   output_clock gen_clk(CLK_OUT);
endmodule

//@
//@ \index{mkAbsoluteClockFull@\te{mkAbsoluteClockFull} (module)|textbf}
//@ \te{mkAbsoluteClockFull} provides a fully parameterizable clock
//@ generation module.
//@ \te{initValue} is held until time start, and then the clock
//@ oscillates with from, with \te{not(initValue)} held for time
//@ \te{compValTime} followed by \te{initValue} held for time
//@ \te{initValTime}.  Hence the clock period after startup is
//@ \te{compValTime + initValTime}.
//@ This module is not synthesizable, it is provided by the Verilog
//@ module \te{ClockGen.v}
//@ # 5
module mkAbsoluteClockFull #( Integer start,
                              Bit#(1) initValue,
                              Integer compValTime,
                              Integer initValTime
                             ) ( Clock );
   (* hide *)
   ClockGenIfc _m <- vMkAbsoluteClockFull(start,
                                          initValue,
                                          compValTime,
                                          initValTime);
   return _m.gen_clk();
endmodule

import "BVI" ClockGen =
module vMkAbsoluteClockFull #( Integer start,
                               Bit#(1) initValue,
                               Integer compValTime,
                               Integer initValTime
                              ) ( ClockGenIfc );
   default_clock no_clock;
   parameter v1Width = compValTime ;
   parameter v2Width = initValTime ;
   parameter initDelay  = start ;
   parameter initValue = initValue ;
   parameter otherValue = ~ initValue ;

   no_reset;
   output_clock gen_clk(CLK_OUT);
endmodule

// The MakeClockIfc supports user-defined clocks with
// irregular waveforms created with mkClock, as opposed to the
// fixed-period waveforms created with the mkAbsoluteClock family.
interface MakeClockIfc#(type one_bit_type);
   method Action       setClockValue(one_bit_type value) ;
   method one_bit_type getClockValue() ;
   method Action       setGateCond(Bool gate) ;
   method Bool         getGateCond() ;
   interface Clock new_clk ;
endinterface

// Internal use only
interface MakeUngatedClockIfc#(type one_bit_type);
   method Action       setClockValue(one_bit_type value) ;
   method one_bit_type getClockValue() ;
   method Action       setGateCond(Bool gate) ;
   method Bool         getGateCond() ;
   method Bool         unused();
   interface Clock new_clk ;
endinterface

//@
//@ \index{mkClock@\te{mkClock} (module)|textbf}
//@ The mkClock module creates a Clock type from a one-bit oscillator
//@ and a Boolean gate condition.
//@ There are no relations between the current clock and the clock
//@ generated by this module.
//@ The initial values of the oscillator and gate are passed
//@ as parameters to the module.  When the module is out of reset,
//@ the oscillator value can be changed using the {\tt setClockValue}
//@ method and the gate condition can be changed by calling the
//@ {\tt setGateCond} method.  The oscillator value and gate condition
//@ can be queried with the {\tt getClockValue} and {\tt getGateCond}
//@ methods, respectively.
//@ The clock created by {\tt mkClock} is available as the
//@ {\tt new_clk} subinterface.
//@ When setting the gate condition, the change does not affect the
//@ generated clock until is low, to prevent glitches.
//@ # 3
module mkClock #( one_bit_type initVal, Bool initGate)
               ( MakeClockIfc#(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1) ) ;

   (* hide *)
   MakeClockIfc#(Bit#(1)) _m <- vMkClock(pack(initVal), initGate);

   method Action setClockValue(one_bit_type value);
     _m.setClockValue(pack(value));
   endmethod

   method one_bit_type getClockValue();
     return unpack(_m.getClockValue());
   endmethod

   method setGateCond = _m.setGateCond;
   method getGateCond = _m.getGateCond;

   interface new_clk = _m.new_clk;
endmodule

import "BVI" MakeClock =
module vMkClock #( Bit#(1) init_osc, Bool init_gate )
                ( MakeClockIfc#(Bit#(1)) );
   parameter initVal = init_osc;
   parameter initGate = pack(init_gate);

   default_clock clk(CLK, (* unused *) CLK_GATE) ;
   default_reset rst(RST) ;

   method setClockValue(CLK_IN) enable(CLK_IN_EN) ;
   method CLK_VAL_OUT getClockValue() ;
   method setGateCond(COND_IN) enable(COND_IN_EN) ;
   method COND_OUT getGateCond() ;

   // clock and gate methods are CF with each other
   schedule setClockValue CF setGateCond;
   schedule setClockValue CF getGateCond;
   schedule getClockValue CF getGateCond;
   schedule getClockValue CF setGateCond;

   // get methods are CF with themselves
   schedule getClockValue CF getClockValue;
   schedule getGateCond   CF getGateCond;

   // get methods sequence before matching set methods
   schedule getClockValue SB setClockValue;
   schedule getGateCond SB setGateCond;

   // we could allow these methods to be SBR, but we choose not to
   schedule setGateCond C setGateCond;
   schedule setClockValue C setClockValue;

   output_clock new_clk(CLK_OUT, CLK_GATE_OUT);
endmodule

// version of mkClock without a gate port
module mkUngatedClock #( one_bit_type initOsc )
                      ( MakeClockIfc#(one_bit_type) ifc )
  provisos( Bits#(one_bit_type, 1) ) ;

   (* hide *)
   MakeUngatedClockIfc#(Bit#(1)) _m <- vMkUngatedClock(pack(initOsc));

   method Action setClockValue(one_bit_type value);
     _m.setClockValue(pack(value));
   endmethod

   method one_bit_type getClockValue();
     return unpack(_m.getClockValue());
   endmethod

   method Action setGateCond (Bool gate);
      error ("The method 'setGateCond' is not provided by the module 'mkUngatedClock'.");
   endmethod

   method getGateCond = True;

   interface new_clk = _m.new_clk;
endmodule

import "BVI" MakeClock =
module vMkUngatedClock #( Bit#(1) init_osc )
                       ( MakeUngatedClockIfc#(Bit#(1)) );
   parameter initVal = init_osc;
   parameter initGate = Bit#(1)'(1);

   default_clock clk(CLK, (* unused *) CLK_GATE) ;
   default_reset rst(RST) ;

   method setClockValue(CLK_IN) enable(CLK_IN_EN) ;
   method CLK_VAL_OUT getClockValue() ;
   // it has these methods, but don't use them
   method setGateCond(COND_IN) enable(COND_IN_EN) ;
   method COND_OUT getGateCond() ;
   method CLK_GATE_OUT unused();

   // clock and gate methods are CF with each other
   schedule setClockValue CF setGateCond;
   schedule setClockValue CF getGateCond;
   schedule getClockValue CF getGateCond;
   schedule getClockValue CF setGateCond;

   // get methods are CF with themselves
   schedule getClockValue CF getClockValue;
   schedule getGateCond   CF getGateCond;

   // get methods sequence before matching set methods
   schedule getClockValue SB setClockValue;
   schedule getGateCond SB setGateCond;

   // we could allow these methods to be SBR, but we choose not to
   schedule setGateCond C setGateCond;
   schedule setClockValue C setClockValue;

   // no one should use unused so tie it down with conflicts
   schedule unused C (unused, setClockValue, getClockValue, setGateCond, getGateCond);
   output_clock new_clk(CLK_OUT);
endmodule


//X@
//X@ \index{GatedClockIfc@\te{GatedClockIfc} (interface)|textbf}
//X@
//X@ # 5
interface GatedClockIfc ;
   method    Action setGateCond(Bool gate) ;
   method    Bool   getGateCond() ;
   interface Clock  new_clk ;
endinterface

//@
//@ \index{mkGatedClock@\te{mkGatedClock} (module)|textbf}
//@ The \te{mkGatedClock} module adds (logic and) a Boolean gate condition
//@ to an existing clock, thus creating another clock in the same family.
//@ The source clock is provided as the argument \tt{clk\_in}.
//@ The gate condition is controlled by an asynchronously-reset register
//@ inside the module.  The register is set with the \tt{setGateCond} Action
//@ method of the interface and can be read with \tt{getGateCond} method.
//@ The reset value of the gate condition register is provided as an
//@ instantiation parameter.  The clock for register (and thus these set
//@ and get methods) is the default clock of the module; to change this
//@ clock use the \tt{clocked\_by} directive.
import "BVI" GatedClock =
//@ # 1
module mkGatedClock#(Bool v) ( Clock clk_in, GatedClockIfc ifc );
   parameter init = pack(v);

   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   default_reset rst(RST) ;

   method setGateCond(COND) enable(COND_EN) ;
   method COND_OUT getGateCond() ;

   schedule getGateCond CF getGateCond;
   schedule getGateCond SB setGateCond;
   // we could allow the method to be SBR with itself, but we choose not to
   schedule setGateCond C setGateCond;

   input_clock clk_in(CLK_IN, CLK_GATE_IN) = clk_in ;
   output_clock new_clk(CLK_OUT, CLK_GATE_OUT);
   ancestor(new_clk, clk_in);
endmodule


//@ For convenience, we provide an alternate version in which the source
//@ clock is the default clock of the module
//@ # 1
module mkGatedClockFromCC#(Bool v) ( GatedClockIfc ifc );
   Clock clk_in <- exposeCurrentClock ;
   (* hide *)
   GatedClockIfc _i <- mkGatedClock(v, clk_in) ;
   return (_i) ;
endmodule


//XXX@ Ravi -- what is the specification for this module?
//XXX@ # 1
module mkJoinedClock #(Clock c)(Clock);
   (* hide *)
   ClockGenIfc _m <- vMkJoinedClock(c);
   return _m.gen_clk();
endmodule

import "BVI" JoinClock =
module vMkJoinedClock #(Clock c)( ClockGenIfc );
  default_clock clk(CLK, CLK_GATE);
  no_reset;
  input_clock c(JOIN_CLK, JOIN_CLK_GATE) = c;
  output_clock gen_clk(CLK_OUT, CLK_GATE_OUT);
  same_family(clk, c);

  ancestor(gen_clk, clk);
  ancestor(gen_clk, c);
endmodule


/////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Clock Multiplexing}
//@ \index{SelectClkIfc@\te{SelectClkIfc} (interface)|textbf}
//@ \index{mkClockMux@\te{mkClockMux} (module)|textbf}
//@ \index{mkClockSelect@\te{mkClockSelect} (module)|textbf}
//@
//@ Bluespec provides two clock multiplexing primitives:  a simple
//@ combinational multiplexor and a stateful module which generates an
//@ appropriate reset signal when the clock changes.

//@ # 4
interface MuxClkIfc ;
   method    Action select ( Bool  ab ) ;
   interface Clock  clock_out ;
endinterface

//
//@ The \te{mkClockMux} module is a simple combinational multiplexor,
//@ which selects between the aClk and bClk.  The provided Verilog module
//@ does not provide any glitch detection or removal logic;  it is the
//@ responsibility of the user to provide additional logic to provide
//@ glitch-free behavior.   The  \te{mkClockMux} module uses three
//@ arguments and provides a Clock interface. The {\tt aClk} is selected if
//@ {\tt ab} is True, while {\tt bClk} is selected otherwise.   The
//@ underlying Verilog
//@ module is {\tt ClockMux.v}.
import "BVI" ClockMux =
//@ # 1
module mkClockMux (Clock aClk, Clock bClk, MuxClkIfc ifcout) ;

   default_clock xclk(CLK, (*unused*)CLKGATE) ;
   no_reset;

   input_clock  aClk(A_CLK, A_CLKGATE) = aClk ;
   input_clock  bClk(B_CLK, B_CLKGATE) = bClk ;

   // Generate the clock output interface
   output_clock clock_out(CLK_OUT, CLK_GATE_OUT) ;

   // other methods
   method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ;
   schedule select C select ;
endmodule

import "BVI" UngatedClockMux =
module mkUngatedClockMux (Clock aClk, Clock bClk, MuxClkIfc ifcout) ;

   default_clock xclk(CLK, (*unused*)CLKGATE) ;
   no_reset;

   input_clock  aClk(A_CLK) = aClk ;
   input_clock  bClk(B_CLK) = bClk ;

   // Generate the clock output interface
   output_clock clock_out(CLK_OUT) ;

   // other methods
   method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ;
   schedule select C select ;

endmodule

//@
//@ The \te{mkClockSelect} module is a clock multiplexor
//@ containing additional logic which generates a reset whenever a new
//@ clock is selected.  As such the interface for the module includes
//@ an \te{Action} method to select the clock (if {\tt ab} is True
//@ clock\_out is taken from {\tt aClk}),
//@ provides a \te{Clock} interface, and also a \te{Reset}
//@ interface. The interface definition is described here.
//@ # 5
interface SelectClkIfc ;
   method    Action select ( Bool  ab ) ;
   interface Clock  clock_out ;
   interface Reset  reset_out ;
endinterface

//
//@ The constructor for the module uses two clock arguments, and
//@ provides the \te{SelectClkIfc} interface.  The underlying Verilog
//@ module is {\tt ClockSelect.v};  it is expected that users can
//@ substitute their own modules to meet any additional requirements
//@ they may have.  The parameter {\tt stages} is the number of clock
//@ cycles in which the reset is asserted after the clock changes.
import "BVI" ClockSelect =
//@ # 5
module mkClockSelect #( Integer stages
                       ) ( Clock aClk,
                           Clock bClk,
                           SelectClkIfc ifcout ) ;

   default_clock xclk(CLK, (*unused*)CLKGATE) ;
   default_reset xrst(RST) ;

   parameter RSTDELAY = (stages >= 0) ? stages :
                        error("Reset synchronizer built with negative number of stage?") ;

   input_clock  aClk(A_CLK, A_CLKGATE) = aClk ;
   input_clock  bClk(B_CLK, B_CLKGATE) = bClk ;

   // Generate the clock output interface
   output_clock clock_out(CLK_OUT, CLK_GATE_OUT) ;

   // Generate the reset output interface
   output_reset reset_out( OUT_RST ) clocked_by(clock_out);

   // other methods
   method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ;
   schedule select C select ;

endmodule

import "BVI" UngatedClockSelect =
module mkUngatedClockSelect #( Integer stages
                              ) ( Clock aClk,
                                  Clock bClk,
                                  SelectClkIfc ifcout ) ;

   default_clock xclk(CLK, (*unused*)CLKGATE) ;
   default_reset xrst(RST) ;

   parameter RSTDELAY = (stages >= 0) ? stages :
                        error("Reset synchronizer built with negative number of stage?") ;

   input_clock  aClk(A_CLK) = aClk ;
   input_clock  bClk(B_CLK) = bClk ;

   // Generate the clock output interface
   output_clock clock_out(CLK_OUT) ;

   // Generate the reset output interface
   output_reset reset_out( OUT_RST ) clocked_by(clock_out);

   // other methods
   method select( SELECT ) enable( SELECT_ENABLE ) reset_by(no_reset) ;
   schedule select C select ;

endmodule


//////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Clock Division}
//@
//@ \index{ClockDividerIfc@\te{ClockDividerIfc} (interface)|textbf}
//@ \index{mkClockDivider@\te{mkClockDivider} (module)|textbf}
//@ \index{mkClockDividerOffset@\te{mkClockDividerOffset} (module)|textbf}
//@ \index{mkClockInverter@\te{mkClockInverter} (module)|textbf}
//@
//@ A clock divider provides a derived clock and also a \te{ClkNextRdy}
//@ signal, which indicates that divided
//@ clock will rise in the next cycle.  This signal is associated with
//@ the input clock, and can only be used within that clock domain.
//@
//@ See {\tt mkSyncRegToSlow}, {\tt mkSyncRegToFast}, {\tt mkSyncFIFOToSlow}, and {\tt mkSyncFIFOToFast}
//@  for some specialized synchronizers
//@ which can be used with divided clocks, and other systems when the
//@ clock edges are known to be aligned.
//@
//@ Define a new type and then the interface
//@ # 1
typedef Bool ClkNextRdy ;

//@ # 5
interface ClockDividerIfc ;
    interface Clock      fastClock ;           // The original clock
    interface Clock      slowClock ;           // The derived clock
    method    ClkNextRdy clockReady() ;        //
endinterface

//@
//@ The {\tt divider} parameter may be any integer greater than 1.
//@ For even dividers the generated clock's duty cycle is 50\%, while
//@ for odd dividers, the duty cycle is $(divider/2) / divider$.  The
//@ current clock (or the clocked\_by argument) is used as the
//@ source clock.
//@
//@ The {\tt  mkClockDividerOffset} module provides a clock divider,
//@ where the rising edge can be defined relative to other clock
//@ dividers which have the same divisor.  An offset of value 2, will
//@ produce a rising edge one fast clock after a divider with offset
//@ 1.   The
//@ {\tt mkClockDivider} modules are provided by the Verilog module
//@ \te{ClockDiv.v}
//@ # 2
module mkClockDivider #( Integer divisor
                        )( ClockDividerIfc ifc ) ;

   Clock currentClock <- exposeCurrentClock ;
   ClockDivider_internal  iifc() ;
   vClockDivider#( divisor )  _idivider( 0, iifc ) ;

   interface slowClock = iifc.slowClock ;
   interface fastClock = currentClock ;
   method clockReady = iifc.clockReady ;
endmodule

module mkGatedClockDivider #( Integer divisor
                             )( ClockDividerIfc ifc ) ;

   Clock currentClock <- exposeCurrentClock ;
   ClockDivider_internal  iifc() ;
   vGatedClockDivider#( divisor )  _idivider( 0, iifc ) ;

   interface slowClock = iifc.slowClock ;
   interface fastClock = currentClock ;
   method clockReady = iifc.clockReady ;
endmodule

//@ # 3
module mkClockDividerOffset #( Integer divisor,
                               Integer offset
                              )( ClockDividerIfc ifc ) ;

   Clock currentClock <- exposeCurrentClock ;
   ClockDivider_internal  iifc() ;
   vClockDivider #( divisor )  _idivider( offset, iifc ) ;

   interface slowClock = iifc.slowClock ;
   interface fastClock = currentClock ;
   method clockReady = iifc.clockReady ;
endmodule

//@ The {\tt mkClockInverter} module generates a inverted clock having
//@ the same period but opposite phase as the source clock.
//@ # 1
module mkClockInverter ( ClockDividerIfc ifc ) ;

   Clock currentClock <- exposeCurrentClock ;
   ClockDivider_internal  iifc() ;
   vClockInverter  _idivider( iifc ) ;

   interface slowClock = iifc.slowClock ;
   interface fastClock = currentClock ;
   method clockReady = iifc.clockReady ;
endmodule

module mkGatedClockInverter ( ClockDividerIfc ifc ) ;

   Clock currentClock <- exposeCurrentClock ;
   ClockDivider_internal  iifc() ;
   vGatedClockInverter  _idivider( iifc ) ;

   interface slowClock = iifc.slowClock ;
   interface fastClock = currentClock ;
   method clockReady = iifc.clockReady ;
endmodule

// internal interface
interface ClockDivider_internal ;
    interface Clock      slowClock ;           // The derived clock
    method    ClkNextRdy clockReady () ;       //
endinterface

import "BVI" ClockInverter =
module vClockInverter ( ClockDivider_internal ifc ) ;

   default_clock clk(CLK_IN) ;
   no_reset ;

   output_clock slowClock(CLK_OUT) ;
   method PREEDGE clockReady()  clocked_by( clk ) reset_by( no_reset ) ;
   schedule clockReady CF clockReady ;
endmodule

module invertCurrentClock(Clock);
   let _m <- mkClockInverter;
   return _m.slowClock;
endmodule: invertCurrentClock


import "BVI" GatedClockInverter =
module vGatedClockInverter ( ClockDivider_internal ifc ) ;

   default_clock clk(CLK_IN, CLK_GATE_IN) ;
   no_reset ;

   output_clock slowClock(CLK_OUT, CLK_GATE_OUT) ;
   method PREEDGE clockReady()  clocked_by( clk ) reset_by( no_reset ) ;
   schedule clockReady CF clockReady ;

endmodule

import "BVI" ClockDiv =
module vClockDivider #( Integer divisor, Integer offseta )
                        ( ClockDivider_internal ifc ) ;
   let logDepth = (divisor > 1) ? log2( divisor ) :
                  error( "mkClockDivider requires a integer > 1 for its clock division" ) ;
   let pwrDepth = 2 ** logDepth ;
   let halfD    = 2 ** (logDepth - 1) ;
   let halfPer  = div( divisor, 2) ;
   let up       = halfD + halfPer - 1 ;
   let lo       = (up + 1) - divisor ;
   let offs     = ((offseta >= 0) &&  (offseta <= (divisor - 1))) ? offseta :
                  ( error( "mkClockDivider requires the offset to be between 0 and the divisor. "
                          + "The offset, " + fromInteger ( offseta ) + ", is greater than or equal to "
                          + "the divisor, " + fromInteger ( divisor ) + "." ) ) ;

   parameter width = logDepth ;
   parameter lower = lo ;
   parameter upper = up ;
   parameter offset = offs ;

   default_clock clk(CLK_IN) ;
   default_reset rst(RST)  ;

   output_clock slowClock(CLK_OUT) ;
   method PREEDGE clockReady()  clocked_by( clk ) reset_by(rst) ;

   schedule clockReady CF clockReady;
endmodule

import "BVI" GatedClockDiv =
module vGatedClockDivider #( Integer divisor, Integer offseta )
                             ( ClockDivider_internal ifc ) ;
   let logDepth = (divisor > 1) ? log2( divisor ) :
                  error( "mkClockDivider requires a integer > 1 for its clock division" ) ;
   let pwrDepth = 2 ** logDepth ;
   let halfD    = 2 ** (logDepth - 1) ;
   let halfPer  = div( divisor, 2) ;
   let up       = halfD + halfPer - 1 ;
   let lo       = (up + 1) - divisor ;
   let offs     = ((offseta >= 0) &&  (offseta <= (divisor - 1))) ? offseta :
                  ( error( "mkClockDivider requires the offset to be between 0 and the divisor. "
                          + "The offset, " + fromInteger ( offseta ) + ", is greater than or equal to "
                          + "the divisor, " + fromInteger ( divisor ) + "." ) ) ;

   parameter width = logDepth ;
   parameter lower = lo ;
   parameter upper = up ;
   parameter offset = offs ;

   default_clock clk(CLK_IN, CLK_GATE_IN) ;
   default_reset rst(RST) ;

   output_clock slowClock(CLK_OUT, CLK_GATE_OUT) ;
   method PREEDGE clockReady() clocked_by( clk ) reset_by(rst) ;

   schedule clockReady CF clockReady;
endmodule

//////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Bit Synchronizers}
//@
//@ \index{SyncBitIfc@\te{SyncBitIfc} (interface)|textbf}
//@ The Sync Bit interface provides a \te{send} method which transmits
//@ one bit of information from one clock domain to the \te{read}
//@ method in a second domain.
//@ # 4
interface SyncBitIfc #(type one_bit_type) ;
   method Action       send ( one_bit_type bitData ) ;
   method one_bit_type read () ;
endinterface


// Synchronize a bit from the current domain to the dClkIn
//@
//@ \index{mkSyncBit@\te{mkSyncBit} (module)|textbf}
//@ \index{mkSyncBit15@\te{mkSyncBit15} (module)|textbf}
//@ \index{mkSyncBit1@\te{mkSyncBit1} (module)|textbf}
//@ The \te{mkSyncBit}, \te{mkSyncBitFromCC} and \te{mkSyncBitToCC} modules provide a
//@ \te{SyncBitIfc} across clock domains.  The send
//@ method is in the one clock domain, and the read method is in
//@ a second clock domain.  The FromCC version and ToCC versions
//@ differ in that the former moves data from the current clock
//@ (module's clock), while
//@ the later move data into the current clock domain
//@   The hardware implementation is a two
//@ register synchronizer, which can be found in SyncBit.v in the
//@ Bluespec Verilog library directory.
//@
//@ The \te{mkSyncBit15} module (one and a half) and its variants provide the same
//@ interface as the \te{mkSyncBit} modules, but the underlying
//@ hardware is slightly modified. For these synchronizers, the first
//@ register clocked by the destination clock triggers on the falling
//@ edge of the clock.  The Verilog can in found in SyncBit15.v in the
//@ Bluespec Verilog library directory.
//@
//@ The \te{mkSyncBit1} module also provides the same interface, but
//@ only uses one register in the destination domain.  Synchronizers
//@ like this, which use with only one
//@ register, are not generally used since meta-stable output
//@ is very probable.  However, one can use this synchronizer provided
//@ special meta-stable resistant flops are selected during physical
//@ synthesis or (for example) if the output is immediately registered.
//@
//@ The \te{mkSyncBit05} module is similar, but the destination register
//@ triggers on the falling edge of the clock.

// A general module which not use the current clock or reset
import "BVI" SyncBit =
module vSyncBit( Clock sClkIn, Reset sRstIn,
                 Clock dClkIn,
                SyncBitIfc#(one_bit_type) ifc )
      provisos( Bits#(one_bit_type, 1)) ;

   default_clock no_clock ;
   no_reset ;

   parameter init =  Bit#(1) '(0);

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method        send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn );
   method dD_OUT read()                     clocked_by ( clk_dst ) reset_by( no_reset);

      schedule read CF read ;
      schedule read CF send ;
      schedule send C  send ;
endmodule

//@
//@ # 4
module mkSyncBit ( Clock sClkIn, Reset sRst,
                   Clock dClkIn,
                   SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule


//@ # 3
module mkSyncBitFromCC ( Clock dClkIn,
                         SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit #(sClk, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule

//@ # 3
module mkSyncBitToCC ( Clock sClkIn, Reset sRstIn,
                       SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock dClk <- exposeCurrentClock ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ;

   return ifc ;
endmodule

// A general module which not use the current clock or reset
import "BVI" SyncBit15 =
module vSyncBit15( Clock sClkIn, Reset sRstIn,
                   Clock dClkIn,
                   SyncBitIfc#(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   default_clock no_clock ;
   no_reset ;

   parameter init = Bit#(1) ' (0);

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method        send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn );
   method dD_OUT read()                     clocked_by ( clk_dst ) reset_by( no_reset);

      schedule read CF read ;
      schedule read CF send ;
      schedule send C  send ;
endmodule

//@
//@ # 4
module mkSyncBit15 ( Clock sClkIn, Reset sRst,
                     Clock dClkIn,
                     SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit15#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule


//@ # 3
module mkSyncBit15FromCC ( Clock dClkIn,
                           SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit15#(sClk, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule

//@ # 3
module mkSyncBit15ToCC ( Clock sClkIn, Reset sRstIn,
                         SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock dClk <- exposeCurrentClock ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit15#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ;

   return ifc ;
endmodule

// A general module which not use the current clock or reset
import "BVI" SyncBit1 =
module vSyncBit1( Clock sClkIn, Reset sRstIn,
                  Clock dClkIn,
                  SyncBitIfc#(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   default_clock no_clock ;
   no_reset ;

   parameter init =  Bit#(1) ' (0);

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method        send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn );
   method dD_OUT read()                     clocked_by ( clk_dst ) reset_by( no_reset);

      schedule read CF read ;
      schedule read CF send ;
      schedule send C  send ;
endmodule

//@
//@ # 4
module mkSyncBit1 ( Clock sClkIn, Reset sRst,
                    Clock dClkIn,
                    SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit1#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule


//@ # 3
module mkSyncBit1FromCC ( Clock dClkIn,
                          SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits #(one_bit_type, 1)) ;

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit1#(sClk, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule

//@ # 3
module mkSyncBit1ToCC ( Clock sClkIn, Reset sRstIn,
                        SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock dClk <- exposeCurrentClock ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit1#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ;

   return ifc ;
endmodule

// A general module which not use the current clock or reset
import "BVI" SyncBit05 =
module vSyncBit05( Clock sClkIn, Reset sRstIn,
                  Clock dClkIn,
                  SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   default_clock no_clock ;
   no_reset ;

   parameter init =  Bit#(1) ' (0);

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method        send ( sD_IN ) enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn );
   method dD_OUT read()                     clocked_by ( clk_dst ) reset_by( no_reset);

      schedule read CF read ;
      schedule read CF send ;
      schedule send C  send ;
endmodule

//@
//@ # 4
module mkSyncBit05 ( Clock sClkIn, Reset sRst,
                     Clock dClkIn,
                     SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit05#(sClkIn, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule


//@ # 3
module mkSyncBit05FromCC ( Clock dClkIn,
                           SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit05#(sClk, sRst, dClkIn) _SyncBit( ifc ) ;

   return ifc ;
endmodule

//@ # 3
module mkSyncBit05ToCC ( Clock sClkIn, Reset sRstIn,
                         SyncBitIfc #(one_bit_type) ifc )
   provisos( Bits#(one_bit_type, 1)) ;

   Clock dClk <- exposeCurrentClock ;

   SyncBitIfc#(one_bit_type) ifc() ;
   vSyncBit05#(sClkIn, sRstIn, dClk) _SyncBit( ifc ) ;

   return ifc ;
endmodule


///////////////////////////////////////////////////////////////////////
// send a pulse across clock domains, send and read are in different domains
//
//@ \subsubsection{Pulse Synchronizers}
//@
//@ \index{SyncPulseIfc@\te{SyncPulseIfc} (interface)|textbf}
//@ The Sync Pulse interface provides an Action \te{send} method which when
//@ invoked causes a pulse on a \te{read} method in a second clock domain.
//@ # 4
interface SyncPulseIfc ;
   method Action send  () ;
   method Bool   pulse () ;
endinterface

import "BVI" SyncPulse =
module vSyncPulse ( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ;
   default_clock no_clock ;
   no_reset ;

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;


   method         send () enable(sEN) clocked_by ( clk_src ) reset_by( sRstIn );
   method dPulse pulse ()             clocked_by ( clk_dst ) reset_by( no_reset) ;

      schedule pulse CF pulse ;
      schedule pulse CF send ;
      schedule send  C  send ;  // 1 bit of send can be conflict free
endmodule

//@
//@ \index{mkSyncPulse@\te{mkSyncPulse} (module)|textbf}
//@ The \te{mkSyncPulse}, \te{mkSyncPulseFromCC} and \te{mkSyncPulseToCC} modules
//@ provide clock domain crossing modules for pulses.  When the
//@ \te{send} method is called from the one clock domain, a pulse will
//@ be seen on the \te{read} method in the second.  Note that there is
//@ no handshaking between the domains, so when sending data
//@ from a fast clock domain to a slower one, not all pulses sent may
//@ be seen in the slower receiving clock domain.  The pulse delay is
//@ two destination clocks cycles.
//@   The hardware implementation can be found in SyncPulse.v in the
//@ Bluespec Verilog library directory.

//@
//@ # 3
module mkSyncPulse ( Clock sClkIn, Reset sRstIn,
                     Clock dClkIn,
                     SyncPulseIfc ifc ) ;

   SyncPulseIfc ifc() ;
   vSyncPulse#(sClkIn, sRstIn, dClkIn) _SyncPulse( ifc ) ;

   return ifc ;
endmodule

//@ # 2
module mkSyncPulseFromCC ( Clock dClkIn,
                           SyncPulseIfc ifc ) ;
   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncPulseIfc ifc() ;
   vSyncPulse#(sClk, sRst, dClkIn) _SyncPulse( ifc ) ;

   return ifc ;
endmodule

//@ # 2
module mkSyncPulseToCC ( Clock sClkIn, Reset sRstIn,
                         SyncPulseIfc ifc ) ;
   Clock dClk <- exposeCurrentClock ;

   SyncPulseIfc ifc() ;
   vSyncPulse#(sClkIn, sRstIn, dClk) _SyncPulse( ifc ) ;

   return ifc ;
endmodule


import "BVI" SyncHandshake =
module vSyncHandshake( Clock sClkIn, Reset sRstIn, Clock dClkIn, SyncPulseIfc ifc ) ;
   default_clock no_clock ;
   no_reset ;

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset rstn_src(sRST) clocked_by (clk_src) = sRstIn ;

   method         send () enable(sEN) ready(sRDY)  clocked_by ( clk_src ) reset_by( rstn_src );
   method dPulse pulse ()                          clocked_by ( clk_dst ) reset_by( no_reset );

   schedule pulse CF pulse ;
   schedule pulse CF send ;
   schedule send  C  send ;  // 1 bit of send can be conflict free

endmodule


//@
//@ \index{mkSyncHandshake@\te{mkSyncHandshake} (module)|textbf}
//@ The \te{mkSyncHandshake}, \te{mkSyncHandshakeFromCC} and \te{mkSyncHandshakeToCC} modules
//@ provide clock domain crossing modules for pulses in a similar way
//@ as \te{mkSyncPulse} modules, except that a handshake is provided
//@ in the \te{mkSyncHandshake} versions. The handshake enforces that
//@ another send does not occur before the first pulse crosses to the
//@ other domain.
//@ The pulse delay from the \te{send} method to the \te{read} method
//@ is two destination clocks.  The \te{send} method is re-enabled in
//@ two destination clock cycles plus two source clock cycles after the
//@ \te{send} method is called.

//@
//@ # 3
module mkSyncHandshake ( Clock sClkIn, Reset sRstIn,
                         Clock dClkIn,
                         SyncPulseIfc ifc ) ;
   SyncPulseIfc ifc() ;
   vSyncHandshake#(sClkIn, sRstIn, dClkIn) _SyncPulse( ifc ) ;

   return ifc ;
endmodule

//@ # 2
module mkSyncHandshakeFromCC ( Clock dClkIn,
                               SyncPulseIfc ifc ) ;
   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncPulseIfc ifc() ;
   vSyncHandshake#(sClk, sRst, dClkIn) _SyncPulse( ifc ) ;

   return ifc ;
endmodule


//@ # 2
module mkSyncHandshakeToCC ( Clock sClkIn, Reset sRstIn,
                             SyncPulseIfc ifc ) ;
   Clock dClk <- exposeCurrentClock ;

   SyncPulseIfc ifc() ;
   vSyncHandshake#(sClkIn, sRstIn, dClk) _SyncPulse( ifc ) ;

   return ifc ;
endmodule

/////////////////////////////////////////////////////////////////////
//@ \subsubsection{Word Synchronizers}
//@
//@ Word synchronizers use the common \te{Reg} interface (redescribed
//@ below), but there
//@ are a few subtle differences which the designer should be aware.
//@ First, the {\em \_read} and {\em \_write} methods are in
//@ difference clock domains, and second the {\em \_write} method
//@ has an implicit ``ready'' condition which means that some
//@ synchronization modules cannot be written every clock cycle. Both
//@ of these conditions are handled automatically by the Bluespec
//@ compiler relieving the designer of these checks.
//@

//@ \begin{libverbatim}
//@ interface Reg #(a_type);
//@     method Action _write(a_type x1);
//@     method a_type _read();
//@ endinterface: Reg
//@ \end{libverbatim}
//@
//@

// internal interface
interface RegI #(type a_type);
    method Action write(a_type x1);
    method a_type read();
endinterface: RegI


// Common import BVI code
import "BVI" SyncRegister =
module vSyncReg#(a initValue) (
                               Clock sClkIn, Reset sRstIn,
                               Clock dClkIn,
                               RegI#(a) ifc )
   provisos (Bits#(a,sa)) ;

   default_clock no_clock ;
   no_reset ;

   parameter width = valueOf( sa ) ;
   parameter init = pack(initValue) ;

   input_clock clk_src( sCLK, (*unused*)sCLK_GATE ) = sClkIn ;
   input_clock clk_dst( dCLK, (*unused*)dCLK_GATE ) = dClkIn ;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method write( sD_IN ) enable (sEN) ready (sRDY)  clocked_by (clk_src) reset_by( sRstIn );
   method dD_OUT read()                             clocked_by (clk_dst) reset_by(no_reset);

      schedule read CF read ;
      schedule read CF write ;
      schedule write C write ;  // unlike our mkReg since reading is in another clock
endmodule

//@ \index{mkSyncReg@\te{mkSyncReg} (module)|textbf}
//@ The \te{mkSyncReg}, \te{mkSyncRegToCC} and \te{mkSyncRegFromCC} modules provide
//@ word synchronization across clock domains.  The crossing are
//@ handshaked, such that a second write cannot occur until the first
//@ is acknowledge by the destination side.  The destination read is
//@ registered.
//@   The hardware implementation can be found in SyncRegister.v in the
//@ Bluespec Verilog library directory.

//@
//@ # 5
module mkSyncReg #( a_type initValue
                   )( Clock sClkIn, Reset sRstIn,
                      Clock dClkIn,
                      Reg #(a_type) ifc )
   provisos (Bits#(a_type,sa) ) ;

   RegI #(a_type) ifci() ;
   vSyncReg#(initValue, sClkIn, sRstIn, dClkIn) _SyncWord( ifci ) ;

   method Action _write(din);
      ifci.write( din ) ;
   endmethod

   method a_type _read() ;
      return ifci.read ;
   endmethod

endmodule

//@ # 4
module mkSyncRegFromCC #( a_type initValue
                         )( Clock dClkIn,
                            Reg #(a_type) ifc)
   provisos (Bits#(a_type,sa)) ;

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   RegI#(a_type) ifci() ;
   vSyncReg#(initValue, sClk, sRst, dClkIn) _SyncWord( ifci ) ;


   method Action _write(din);
      ifci.write( din ) ;
   endmethod

   method a_type _read() ;
      return ifci.read ;
   endmethod

endmodule

//@ # 4
module mkSyncRegToCC #( a_type initValue
                       )( Clock sClkIn, Reset sRstIn,
                          Reg #(a_type) ifc)
   provisos (Bits#(a_type,sa)) ;

   Clock dClk <- exposeCurrentClock ;

   RegI#(a_type) ifci() ;
   vSyncReg#(initValue, sClkIn, sRstIn, dClk) _SyncWord( ifci ) ;

   method Action _write(din);
      ifci.write( din ) ;
   endmethod

   method a_type _read() ;
      return ifci.read ;
   endmethod

endmodule

/////////////////////////////////////////////////////////////////////
//@ \subsubsection{FIFO Synchronizers}
//@
//@ \index{SyncFIFOIfc@\te{SyncFIFOIfc} (interface)|textbf}
//@ The sync FIFO interface defines an interface similar to the FIFOF
//@ interface, except it does not have a clear method.
//@ # 5
interface SyncFIFOIfc #(type a_type) ;
   method Action enq ( a_type sendData ) ;
   method Action deq () ;
   method a_type first () ;
   method Bool notFull () ;
   method Bool notEmpty () ;
endinterface

// Internal interface for zero-width SyncFIFO
interface SyncFIFO0Ifc;
   method Action enq () ;
   method Action deq () ;
   method Bool notFull () ;
   method Bool notEmpty () ;
endinterface

import "BVI" SyncFIFO =
module vSyncFIFO #(Integer depthIn
                  )(
                    Clock sClkIn, Reset sRstIn,
                    Clock dClkIn,
                    SyncFIFOIfc #(a) ifc)

   provisos (Bits#(a,sa));

   let logDepth = log2( depthIn ) ;
   let pwrDepth = 2 ** logDepth ;

   if (pwrDepth < 2)
      error( "mkSyncFIFO depth must be greater than 1 for correct operation" ) ;

   parameter dataWidth = valueOf( sa ) ;
   parameter depth = pwrDepth ; // must be power of 2 !
   parameter indxWidth = logDepth ;

   default_clock no_clock ;
   no_reset ;

   input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn;
   input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method enq ( sD_IN )  ready(sFULL_N)  enable(sENQ) clocked_by(clk_src) reset_by(sRstIn);
   method deq ()         ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset);
   method dD_OUT first() ready(dEMPTY_N)              clocked_by(clk_dst) reset_by(no_reset);
   method dEMPTY_N notEmpty()                         clocked_by(clk_dst) reset_by(no_reset);
   method sFULL_N notFull()                           clocked_by(clk_src) reset_by(sRstIn);

      schedule first SB deq;
      schedule first CF (notFull, notEmpty, enq, first);
      schedule notFull CF (notEmpty, notFull, deq);
      //schedule (notFull, notEmpty) SB (enq, deq);
      schedule notFull SB enq;
      schedule notEmpty SB deq;
      schedule notEmpty CF (notEmpty, enq);
      schedule enq CF deq;
      schedule deq C deq;
      schedule enq C enq;

endmodule

// Version for depth 1
import "BVI" SyncFIFO1 =
module vSyncFIFO1 (
                    Clock sClkIn, Reset sRstIn,
                    Clock dClkIn,
                    SyncFIFOIfc #(a) ifc)

   provisos (Bits#(a,sa));

   parameter dataWidth = valueOf( sa ) ;
   default_clock no_clock ;
   no_reset ;

   input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn;
   input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method enq ( sD_IN )  ready(sFULL_N)  enable(sENQ) clocked_by(clk_src) reset_by(sRstIn);
   method deq ()         ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset);
   method dD_OUT first() ready(dEMPTY_N)              clocked_by(clk_dst) reset_by(no_reset);
   method dEMPTY_N notEmpty()                         clocked_by(clk_dst) reset_by(no_reset);
   method sFULL_N notFull()                           clocked_by(clk_src) reset_by(sRstIn);

      schedule first SB deq;
      schedule first CF (notFull, notEmpty, enq, first);
      schedule notFull CF (notEmpty, notFull, deq);
      schedule notFull SB enq;
      schedule notEmpty SB deq;
      schedule notEmpty CF (notEmpty, enq);
      schedule enq CF deq;
      schedule deq C deq;
      schedule enq C enq;

endmodule

// Version for data width 0
import "BVI" SyncFIFO0 =
module vSyncFIFO0 #(Integer depthIn
                  )(
                    Clock sClkIn, Reset sRstIn,
                    Clock dClkIn,
                    SyncFIFO0Ifc ifc);

   let logDepth = log2( depthIn ) ;
   let pwrDepth = 2 ** logDepth ;

   if (pwrDepth < 2)
      error( "mkSyncFIFO depth must be greater than 1 for correct operation" ) ;

   parameter depth = pwrDepth ; // must be power of 2 !
   parameter indxWidth = logDepth ;

   default_clock no_clock ;
   no_reset ;

   input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn;
   input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method enq ()         ready(sFULL_N)  enable(sENQ) clocked_by(clk_src) reset_by(sRstIn);
   method deq ()         ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset);
   method dEMPTY_N notEmpty()                         clocked_by(clk_dst) reset_by(no_reset);
   method sFULL_N notFull()                           clocked_by(clk_src) reset_by(sRstIn);

      schedule notFull CF (notEmpty, notFull, deq);
      //schedule (notFull, notEmpty) SB (enq, deq);
      schedule notFull SB enq;
      schedule notEmpty SB deq;
      schedule notEmpty CF (notEmpty, enq);
      schedule enq CF deq;
      schedule deq C deq;
      schedule enq C enq;

endmodule

// Version for depth 1, data width 0
import "BVI" SyncFIFO10 =
module vSyncFIFO10 (
                    Clock sClkIn, Reset sRstIn,
                    Clock dClkIn,
                    SyncFIFO0Ifc ifc);

   default_clock no_clock ;
   no_reset ;

   input_clock clk_src ( sCLK, (*unused*)sCLK_GATE ) = sClkIn;
   input_clock clk_dst ( dCLK, (*unused*)dCLK_GATE ) = dClkIn;

   input_reset (sRST) clocked_by (clk_src) = sRstIn ;

   method enq ()         ready(sFULL_N)  enable(sENQ) clocked_by(clk_src) reset_by(sRstIn);
   method deq ()         ready(dEMPTY_N) enable(dDEQ) clocked_by(clk_dst) reset_by(no_reset);
   method dEMPTY_N notEmpty()                         clocked_by(clk_dst) reset_by(no_reset);
   method sFULL_N notFull()                           clocked_by(clk_src) reset_by(sRstIn);

      schedule notFull CF (notEmpty, notFull, deq);
      schedule notFull SB enq;
      schedule notEmpty SB deq;
      schedule notEmpty CF (notEmpty, enq);
      schedule enq CF deq;
      schedule deq C deq;
      schedule enq C enq;

endmodule


//@
//@ \index{mkSyncFIFO@\te{mkSyncFIFO} (module)|textbf}
//@ The \te{mkSyncFIFO}, \te{mkSyncFIFOFromCC} and \te{mkSyncFIFOToCC} modules
//@ provide FIFOs for sending data across clock domains.
//@ The \te{enq} method is in one domain, while the \te{deq} and
//@ \te{first} methods are in a second domain.
//@ Depth of the instantiated FIFO may be increased to the next
//@ power of 2, FIFOs of depth 1 are allowed.
//@   The hardware implementation can be found in SyncFIFO.v in the
//@ Bluespec Verilog library directory.

//@
//@ # 5
module mkSyncFIFO #( Integer depthIn
                    )( Clock sClkIn, Reset sRstIn,
                       Clock dClkIn,
                       SyncFIFOIfc #(a_type) ifc )
   provisos (Bits#(a_type,sa));

   SyncFIFOIfc#(a_type) _ifc;
   if (valueOf(sa) == 0) begin
      (*hide*)
      SyncFIFO0Ifc _vifc <- (depthIn == 1) ?
                            vSyncFIFO10(sClkIn, sRstIn, dClkIn) :
			    vSyncFIFO0(depthIn, sClkIn, sRstIn, dClkIn) ;
      _ifc = (interface SyncFIFOIfc;
	         method enq (sendData) = _vifc.enq() ;
		 method deq ()         = _vifc.deq() ;
		 method first ()       = ? ;
		 method notFull        = _vifc.notFull ;
		 method notEmpty       = _vifc.notEmpty ;
	      endinterface) ;
   end
   else begin
     (*hide*)
      _ifc <- (depthIn == 1) ?
              vSyncFIFO1(sClkIn, sRstIn, dClkIn) :
	      vSyncFIFO(depthIn, sClkIn, sRstIn, dClkIn) ;
   end

   return _ifc ;
endmodule


//@ A variation of the Sync FIFO which allow the empty and full
//@ signals to be registered.  Registering the signals can give better
//@ synthesis results, since a comparator is removed from the empty or
//@ full path.  However, there is an additional cycle of latency
//@ before the empty or full signal is visible.
//@ # 7
(* deprecate = "This module is deprecated,  use mkSyncFIFO instead" *)
module mkSyncFIFOFull #( Integer depthIn,
                         Bool regEmpty,
                         Bool regFull
                        )( Clock sClkIn, Reset sRstIn,
                           Clock dClkIn,
                           SyncFIFOIfc #(a_type) ifc )
   provisos (Bits#(a_type,sa));

   SyncFIFOIfc#(a_type) ifc ;
   if (regEmpty && regFull) begin
      ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClkIn) ;
   end
   else begin
      ifc = error ("mkSyncFIFOFull can only be used when regEmpty and regFull are both True.");
   end
   return ifc ;
endmodule


//@ # 4
module mkSyncFIFOFromCC #( Integer depthIn
                          )( Clock dClkIn,
                             SyncFIFOIfc #(a_type) ifc)
   provisos (Bits#(a_type,sa));

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   (*hide*)
   SyncFIFOIfc#(a_type) _ifc <- mkSyncFIFO(depthIn, sClk, sRst, dClkIn) ;

   return _ifc ;
endmodule


//@ # 4
module mkSyncFIFOToCC #( Integer depthIn
                        )( Clock sClkIn, Reset sRstIn,
                           SyncFIFOIfc #(a_type) ifc)
   provisos (Bits#(a_type,sa));

   Clock dClk <- exposeCurrentClock ;

   (*hide*)
   SyncFIFOIfc#(a_type) _ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClk) ;

   return _ifc ;
endmodule

//@  # 6
(* deprecate = "This module is deprecated,  use mkSyncFIFOFromCC instead" *)
module mkSyncFIFOFromCCFull #( Integer depthIn,
                               Bool regEmpty,
                               Bool regFull
                              )( Clock dClkIn,
                                 SyncFIFOIfc #(a_type) ifc)
   provisos (Bits#(a_type,sa));

   Clock sClk <- exposeCurrentClock ;
   Reset sRst <- exposeCurrentReset ;

   SyncFIFOIfc#(a_type) ifc ;
   if (regEmpty && regFull) begin
      ifc <- mkSyncFIFO(depthIn, sClk, sRst, dClkIn);
   end
   else begin
      ifc = error ("mkSyncFIFOFromCCFull can only be used when regEmpty and regFull are both True.");
   end
   return ifc ;
endmodule


//@ # 6
(* deprecate = "This module is deprecated,  use mkSyncFIFOToCC instead" *)
module mkSyncFIFOToCCFull #( Integer depthIn,
                             Bool regEmpty,
                             Bool regFull
                            )( Clock sClkIn, Reset sRstIn,
                               SyncFIFOIfc #(a_type) ifc)
   provisos (Bits#(a_type,sa));

   Clock dClk <- exposeCurrentClock ;

   SyncFIFOIfc#(a_type) ifc ;
   if (regFull && regEmpty) begin
      ifc <- mkSyncFIFO(depthIn, sClkIn, sRstIn, dClk) ;
   end
   else begin
      ifc = error ("mkSyncFIFOFromCCFull can only be used when regEmpty and regFull are both True.");
   end

   return ifc ;
endmodule

/////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Asynchronous RAMs}
//@ \index{DualPortRamIfc@\te{DualPortRamIfc} (interface)|textbf}
//@ \index{mkDualRam@\te{mkDualRam} (module)|textbf}
//@
//@ # 4
interface DualPortRamIfc #(type addr_t, type data_t);
   method Action      write( addr_t wr_addr, data_t  din );
   method data_t      read ( addr_t rd_addr);
endinterface: DualPortRamIfc

import "BVI" DualPortRam =
//@ # 3
module mkDualRam( DualPortRamIfc #(addr_t, data_t) )
   provisos ( Bits#(addr_t,sa),
              Bits#(data_t,da) ) ;

   parameter addrWidth = valueOf(sa);
   parameter dataWidth = valueOf(da);

   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   no_reset ;

   method      write(WADDR, DIN) enable(WE) clocked_by( clk )      reset_by( no_reset ) ;
   method DOUT read(RADDR)                  clocked_by( no_clock ) reset_by( no_reset ) ;

   // read and write are independent
      schedule write CF read ;
      schedule read  CF read ;
      schedule write C write ;
endmodule

/////////////////////////////////////////////////////////////////////////
//@ \subsubsection{A Crossing Primitive using Only Wires}

(* deprecate = "Replaced by mkNullCrossingWire" *)
import "BVI" SyncWire =
//@ # 3
module mkNullCrossing( Clock dClk, a_type dataIn,
                       ReadOnly#(a_type) ifc )
   provisos (Bits#(a_type, sizeOfa)) ;

   default_clock no_clock;
   no_reset;

   parameter width = valueOf( sizeOfa ) ;

   input_clock ssClk() = clockOf(dataIn);
   input_reset ssRst() = resetOf(dataIn);

   input_clock ddClk() = dClk;

   port DIN clocked_by( ssClk ) reset_by( ssRst ) = dataIn ;
   method DOUT _read() clocked_by( ddClk ) reset_by( no_reset ) ;

      schedule   _read CF _read ;

endmodule

// An undocumented (for now) primitive that implements a
// working null crossing in both Verilog and Bluesim

import "BVI" CrossingBypassWire =
   module vMkCrossingBypassWire (Clock dClk, VWire#(a) ifc)
      provisos (Bits#(a,sa));
      parameter width = valueOf(sa);
      no_reset;
      default_clock clk(CLK, (*unused*) GATE);
      input_clock dstClk() = dClk;
      method wset(WVAL) enable((*inhigh*)WSET);
      method WGET wget clocked_by( dstClk ) reset_by( no_reset );
      schedule wset C  wset ;
      schedule wget CF wget ;
      path (WVAL, WGET) ;
      unsync wget ;
   endmodule: vMkCrossingBypassWire

module mkBypassCrossingWire#(Clock dClk)
                            (Tuple2#(Wire#(data_t), Maybe#(Name__)))
                            provisos (Bits#(data_t, data_t_size));
   // using VWire is an ugly hack to work around
   // the _read desugaring
   VWire#(data_t) ifc;
   Maybe#(Name__) mname = Nothing;
   if (valueOf(data_t_size) == 0)
      begin
         ifc = (interface VWire
                   method Action wset(x);
                     noAction;
                   endmethod
                   method wget = unpack(0);
                endinterface);
      end
   else
      begin
         VWire#(data_t) _r() ;
         vMkCrossingBypassWire __(dClk,_r) ;
	 Name__ nm = primGetModuleName(asIfc(_r));
         mname = tagged Valid nm;
         ifc = _r;
      end

   Reg#(data_t) ifc2 = interface Reg
                         method _write = ifc.wset;
                         method _read = ifc.wget;
		       endinterface;

   return (tuple2(asIfc(ifc2), mname));

endmodule: mkBypassCrossingWire


module mkNullCrossingWire(Clock dClk, a_type dataIn, ReadOnly#(a_type) ifc)
   provisos (Bits#(a_type, sizeOfa)) ;

   if (valueOf(sizeOfa) == 0)
   begin

      method a_type _read();
	 return unpack('0);
      endmethod

   end
   else
   begin

   List#(Clock) sourceClks = clocksOf(pack(dataIn));

   if(isNull(sourceClks)) begin
      String msg = "Attempt to synchronize an unclocked value with nullCrossingWire ";
      // bogus wire only used to get a name for the error message
      Tuple2#(Wire#(Bit#(1)), Maybe#(Name__)) _blob <- mkBypassCrossingWire(dClk, clocked_by dClk);
      String name_str = "<unknown>";
      Position__ name_pos = noPosition;
      if (tpl_2(_blob) matches tagged Valid .name) begin
	 name_str = "\140" + primGetNameString(name) + "'";
	 name_pos = primGetNamePosition(name);
      end
      String full_msg = msg + name_str + ".";
      primGenerateError(7,name_pos,full_msg);
   end

   Clock sClk = head(sourceClks);

   (*hide*)  let _crossed <- mkBypassCrossingWire(dClk, clocked_by sClk);
   match {._w, ._mname} = _crossed;

   if(_mname matches tagged Valid .name) chkClockDomain(name, "nullCrossingWire", dataIn);
   // if there is no name, the "bad" error message is the best we can do

   (* can_schedule_first *)
   (* clock_crossing_rule *)
   rule clock_domain_crossing;
      _w <= dataIn;
   endrule: clock_domain_crossing

   method _read = _w;

   end

endmodule: mkNullCrossingWire

interface CrossingReg #( type a ) ;
   method Action _write(a datain) ;
   method a      _read() ;
   method a      crossed() ;
endinterface

function a readCrossingRegSrc(CrossingReg#(a) ifc);
   return ifc._read();
endfunction

function a readCrossingRegDst(CrossingReg#(a) ifc);
   return ifc.crossed();
endfunction

function Action writeCrossingReg(CrossingReg#(a) ifc, a x);
   action
      ifc._write(x);
   endaction
endfunction

function Reg#(a) crossingRegToReg(CrossingReg#(a) ifc);
   return (interface Reg
	      method _read = ifc._read;
	      method _write = ifc._write;
	   endinterface);
endfunction

function ReadOnly#(a) crossingRegSrcToReadOnly(CrossingReg#(a) ifc);
   return (interface ReadOnly
	      method _read = ifc._read;
	   endinterface);
endfunction

function ReadOnly#(a) crossingRegDstToReadOnly(CrossingReg#(a) ifc);
   return (interface ReadOnly
	      method _read = ifc.crossed;
	   endinterface);
endfunction


// for data width == 0 (pointless, but included for generality)
module vMkNullCrossing0(Clock dstClk, CrossingReg#(a) ifc)
   provisos(Bits#(a, sz_a));

   method Action _write(a x) = noAction;
   method a _read()   = unpack(0);
   method a crossed() = unpack(0);
endmodule

// only for data width > 0
import "BVI" CrossingRegN =
module vMkNullCrossingReg( Clock dstClk, a initVal, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   default_clock sClk (CLK, (*unused*) GATE);
   default_reset sRst (RST);

   parameter width = valueOf(sz_a) ;
   parameter init  = pack(initVal);

   input_clock dClk() = dstClk;

   method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(sRst);
   method Q_OUT _read() clocked_by(sClk) reset_by(sRst) ;
   method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ;

   schedule   _write  C  _write ;
   schedule   _read   CF _read ;
   schedule   _read   SB _write;
   schedule   crossed CF crossed ;
endmodule

// only for data width > 0
import "BVI" CrossingRegA =
module vMkNullCrossingRegA( Clock dstClk, a initVal, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   default_clock sClk (CLK, (*unused*) GATE);
   default_reset sRst (RST);

   parameter width = valueOf(sz_a) ;
   parameter init  = pack(initVal);

   input_clock dClk() = dstClk;

   method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(sRst);
   method Q_OUT _read() clocked_by(sClk) reset_by(sRst) ;
   method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ;

   schedule   _write  C  _write ;
   schedule   _read   CF _read ;
   schedule   _read   SB _write;
   schedule   crossed CF crossed ;
endmodule

// only for data width > 0
import "BVI" CrossingRegUN =
module vMkNullCrossingRegU( Clock dstClk, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   default_clock sClk (CLK, (*unused*) GATE);
   no_reset;

   parameter width = valueOf(sz_a) ;

   input_clock dClk() = dstClk;

   method _write(D_IN) enable(EN) clocked_by(sClk) reset_by(no_reset);
   method Q_OUT _read() clocked_by(sClk) reset_by(no_reset);
   method Q_OUT crossed() clocked_by(dClk) reset_by(no_reset) ;

   schedule   _write  C  _write ;
   schedule   _read   CF _read ;
   schedule   _read   SB _write;
   schedule   crossed CF crossed ;
endmodule

module mkNullCrossingReg( Clock dstClk, a initVal, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   CrossingReg#(a) _ifc;

   if (valueOf(sz_a) == 0)
      (*hide*)
      _ifc <- vMkNullCrossing0(dstClk);
   else
      (*hide*)
      _ifc <- vMkNullCrossingReg(dstClk,initVal);

   return _ifc;
endmodule: mkNullCrossingReg

module mkNullCrossingRegA( Clock dstClk, a initVal, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   CrossingReg#(a) _ifc;

   if (valueOf(sz_a) == 0)
      (*hide*)
      _ifc <- vMkNullCrossing0(dstClk);
   else
      (*hide*)
      _ifc <- vMkNullCrossingRegA(dstClk,initVal);

   return _ifc;
endmodule: mkNullCrossingRegA

module mkNullCrossingRegU( Clock dstClk, CrossingReg#(a) ifc )
   provisos (Bits#(a, sz_a)) ;

   CrossingReg#(a) _ifc;

   if (valueOf(sz_a) == 0)
      (*hide*)
      _ifc <- vMkNullCrossing0(dstClk);
   else
      (*hide*)
      _ifc <- vMkNullCrossingRegU(dstClk);

   return _ifc;
endmodule: mkNullCrossingRegU

/////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Specialized Crossing Primitives}
//@
//@ \index{mkSyncRegToSlow@\te{mkSyncRegToSlow} (module)|textbf}
//@ \index{mkSyncRegToFast@\te{mkSyncRegToFast} (module)|textbf}
//@ \index{mkSyncFIFOToSlow@\te{mkSyncRegToSlow} (module)|textbf}
//@ \index{mkSyncFIFOToFast@\te{mkSyncRegToFast} (module)|textbf}
//@

// a Wrapper for RegAligned (duplicate of RegA where read and write
// methods are in different domains)
import "BVI" RegAligned =
module vSyncRegAligned #( a_type  initValue) (
                                             Clock sClkIn, Reset sRstIn,
                                             Clock dClkIn, Reset dRstIn,
                                             Clock realClock, Reset realReset,
                                             Reg#(a_type) ifc )
   provisos (Bits#(a_type,sizea)) ;

   parameter width = valueOf( sizea ) ;
   parameter init = pack(initValue) ;

   default_clock ( CLK, (*unused*)CLK_GATE ) = realClock;
   default_reset( RST ) = realReset ;

   input_clock clk_src( ) = sClkIn ;
   input_clock clk_dst( ) = dClkIn ;

   input_reset srst() clocked_by (clk_src) = sRstIn ;
   input_reset drst() clocked_by (clk_dst) = dRstIn ;

   method       _write( D_IN ) enable(EN)  clocked_by( clk_src ) reset_by(srst) ;
   method Q_OUT _read()                    clocked_by( clk_dst ) reset_by(drst) ;

      schedule _read CF _read ;
      schedule _read CF _write ;
      // Do not allow EXT for the _write method !
      schedule _write C _write ;
endmodule

//@ The {\tt mkSyncRegToSlow} and {\tt mkSyncSyncRegToFast} are specialized crossing primitives
//@ which can be used to transport data when clock edges are aligned,
//@ between the domains. The divided clocks and the appropriate
//@ interface needed for the module would typically be
//@ generated using the {\tt mkClockDivider} module.
//@
//@ The crossing primitive is implemented via a single register,
//@ clocked by slower (divided) clock.  For a fast  to slow crossing, the register is only writable when {\tt
//@ clockReady} bit of the divider interface is asserted.  This is an implicit condition of the
//@ module which prevent erroneous writes.  For a slow to fast
//@ crossing both the read and write methods are always available.
//@
//@ # 5
module mkSyncRegToSlow #( a_type initValue
                         )( ClockDividerIfc divider,
                            Reset slowRstIn,
                            Reg #(a_type) ifc )
   provisos (Bits#(a_type,sizea)) ;

   Reg#(a_type) icrossReg() ;
   vSyncRegAligned#(initValue)  crossREGsrc( divider.fastClock, noReset,
                                          divider.slowClock, slowRstIn,
                                          divider.slowClock, slowRstIn,
                                          icrossReg ) ;

   method _read () ;
      return icrossReg._read() ;
   endmethod

   // Write method is only available in the fast cycle before the slow clock rises
   method Action _write( a_type din ) if ( divider.clockReady ) ;
      icrossReg._write( din ) ;
   endmethod

endmodule

module mkSyncRegToFast #( a_type initValue
                         )( ClockDividerIfc divider,
                            Reset slowRstIn,
                            Reg #(a_type) ifc )
   provisos (Bits#(a_type,sizea)) ;

   Reg#(a_type) icrossReg() ;
   vSyncRegAligned#(initValue)  crossREGdst( divider.slowClock, slowRstIn,
                                          divider.fastClock, noReset,
                                          divider.slowClock, slowRstIn,
                                          icrossReg ) ;

   // _read method is always available in the fast domain
   method _read () ;
      return icrossReg._read() ;
   endmethod

   // Write method is always available from the slow domain
   method Action _write( a_type din ) ;
      icrossReg._write( din ) ;
   endmethod

endmodule


///  Build a fifo crossing in the same way
interface FIFOF_MC #(type a) ;
    method Action enq(a x1) ;
    method Action deq() ;
    method a first() ;
    method Bool notFull() ;
    method Bool i_notFull() ;
    method Bool notEmpty() ;
    method Bool i_notEmpty() ;
endinterface


// Depth >2, width > 0.
import "BVI" SizedFIFO =
module vFIFOFS_MC#( Integer depth ) (
                                       Clock sClkIn, Reset sRstIn,
                                       Clock dClkIn, Reset dRstIn,
                                       Clock realClock,  Reset realReset,
                                       FIFOF_MC#(a) ifc )
   provisos (Bits#(a,sa));

   parameter p1width = valueOf(sa);
   parameter p2depth = depth;
   parameter p3cntr_width = log2(depth-1);

   default_clock clk ( CLK, (*unused*)CLK_GATE ) = realClock;
   default_reset _rst__ ( RST ) = realReset ;

   input_clock clk_src( ) = sClkIn ;
   input_reset srst() clocked_by (clk_src) = sRstIn ;

   input_clock clk_dst( ) = dClkIn ;
   input_reset drst() clocked_by (clk_dst) = dRstIn ;

    method          enq( D_IN ) enable(ENQ) clocked_by( clk_src ) reset_by( srst ) ;
    method FULL_N   notFull                 clocked_by( clk_src ) reset_by( srst ) ;
    method FULL_N   i_notFull               clocked_by( clk_src ) reset_by( srst ) ;

    method          deq()       enable(DEQ) clocked_by( clk_dst ) reset_by( drst ) ;
    method D_OUT    first                   clocked_by( clk_dst ) reset_by( drst ) ;
    method EMPTY_N  notEmpty                clocked_by( clk_dst ) reset_by( drst ) ;
    method EMPTY_N  i_notEmpty              clocked_by( clk_dst ) reset_by( drst ) ;

    // method          clear()  ;
    port   CLR = pack(False) ;          // Don't know which side clear belongs

    // Cross domain methods are CF
       // this has some implications that loopy fifos are not allowed.
       schedule (enq, notFull, i_notFull) CF (deq, first, notEmpty, i_notEmpty ) ;

       schedule deq CF (i_notEmpty) ;
       schedule enq CF (i_notFull) ;
       schedule (first, notEmpty) CF
                 (first, i_notEmpty, notEmpty) ;

       schedule (notFull) CF
                 (i_notFull, notFull) ;

       schedule (i_notEmpty) CF
                ( first, i_notEmpty, notEmpty) ;
       schedule (i_notFull) CF
                ( i_notFull, notFull) ;

       schedule first SB deq ;
       schedule (notEmpty) SB (deq) ;
       schedule (notFull) SB (enq) ;

       schedule deq C deq;
       schedule enq C enq;

// Following taken from FIFOF_.bsv
//     schedule deq CF (enq, i_notEmpty, i_notFull) ;
//     schedule enq CF (deq, first, i_notEmpty, i_notFull) ;
//     schedule (first, notEmpty, notFull) CF
//                (first, i_notEmpty, i_notFull, notEmpty, notFull) ;
//     schedule (i_notEmpty, i_notFull) CF
//                (clear, first, i_notEmpty, i_notFull, notEmpty, notFull) ;
//     schedule (clear, deq, enq) SB clear ;
//     schedule first SB (clear, deq) ;
//     schedule (notEmpty, notFull) SB (clear, deq, enq) ;
  endmodule



// Depth == 2, width > 0.

import "BVI" FIFO2 =
module vFIFOF2_MC                  (
                                       Clock sClkIn, Reset sRstIn,
                                       Clock dClkIn, Reset dRstIn,
                                       Clock realClock,  Reset realReset,
                                       FIFOF_MC#(a) ifc )
   provisos (Bits#(a,sa));

   parameter width = valueOf(sa);

   default_clock clk ( CLK, (*unused*)CLK_GATE ) = realClock;
   default_reset _rst__ ( RST ) = realReset ;

   input_clock clk_src( ) = sClkIn ;
   input_reset srst() clocked_by (clk_src) = sRstIn ;

   input_clock clk_dst( ) = dClkIn ;
   input_reset drst() clocked_by (clk_dst) = dRstIn ;

    method          enq( D_IN ) enable(ENQ) clocked_by( clk_src ) reset_by( srst ) ;
    method FULL_N   notFull                 clocked_by( clk_src ) reset_by( srst ) ;
    method FULL_N   i_notFull               clocked_by( clk_src ) reset_by( srst ) ;

    method          deq()       enable(DEQ) clocked_by( clk_dst ) reset_by( drst ) ;
    method D_OUT    first                   clocked_by( clk_dst ) reset_by( drst ) ;
    method EMPTY_N  notEmpty                clocked_by( clk_dst ) reset_by( drst ) ;
    method EMPTY_N  i_notEmpty              clocked_by( clk_dst ) reset_by( drst ) ;

    // method          clear()  ;
    port   CLR = pack(False) ;          // Don't know which side clear belongs

    // Cross domain methods are CF
       // this has some implications that loopy fifos are not allowed.
       schedule (enq, notFull, i_notFull) CF (deq, first, notEmpty, i_notEmpty ) ;

       schedule deq CF (i_notEmpty) ;
       schedule enq CF (i_notFull) ;
       schedule (first, notEmpty) CF
                 (first, i_notEmpty, notEmpty) ;

       schedule (notFull) CF
                 (i_notFull, notFull) ;

       schedule (i_notEmpty) CF
                ( first, i_notEmpty, notEmpty) ;
       schedule (i_notFull) CF
                ( i_notFull, notFull) ;

       schedule first SB deq ;
       schedule (notEmpty) SB (deq) ;
       schedule (notFull) SB (enq) ;
       schedule deq C deq;
       schedule enq C enq;

  endmodule


module vFIFOF_MC#( Integer depth) (
                                   Clock sClkIn, Reset sRstIn,
                                   Clock dClkIn, Reset dRstIn,
                                   Clock realClock,  Reset realReset,
                                   FIFOF_MC#(a) ifc )
   provisos( Bits#(a,sa) ) ;

   (* hide *)
   FIFOF_MC#(a) _ifc <- (depth < 2 ) ? error( "Error SyncFIFO sizes must be 2 or greater" ) :
                         ( depth == 2) ?
                          vFIFOF2_MC ( sClkIn, sRstIn, dClkIn, dRstIn, realClock, realReset )
                           :
                          vFIFOFS_MC (depth,  sClkIn, sRstIn, dClkIn, dRstIn, realClock, realReset ) ;
   return _ifc ;
endmodule

//@ The {\tt mkSyncFIFOAlignedEdges} module is a specialized crossing
//@ primitive which can be used to transport data when clock edges are
//@ aligned, between a fast
//@ sClkIn and a slower dClkIn. The derived clock and the
//@ \te{ClkNextRdy} signal would typically be
//@ generated using the {\tt mkClockDivider} module.
//@
//@ The crossing primitive is implemented via a FIFO with the
//@ specified depth
//@ clocked by dClkIn.  The FIFO  is only writable when {\tt
//@ syncBit} is asserted and the FIFO is not Full.
//@
//@ # 5
module mkSyncFIFOToSlow #( Integer depth
                          )( ClockDividerIfc divider,
                             Reset slowRstIn,
                             SyncFIFOIfc #(a_type) ifc )
   provisos (Bits#(a_type,sizea)) ;

   FIFOF_MC#(a_type)        cross_fifo() ;
   vFIFOF_MC#( depth )   crossFIFOsrc( divider.fastClock, noReset,
                                      divider.slowClock, slowRstIn,
                                      divider.slowClock, slowRstIn,
                                      cross_fifo ) ;

   method Bool notFull =  (cross_fifo.i_notFull && divider.clockReady ) ;

   method Action enq( a_type din ) if (cross_fifo.i_notFull && divider.clockReady ) ;
      cross_fifo.enq( din ) ;
   endmethod

   // Deq and first are clocked by the slow clock, and hence have
   // usual valid condition
   method Bool notEmpty = cross_fifo.i_notEmpty;

   method Action deq() if (cross_fifo.i_notEmpty ) ;
      cross_fifo.deq( ) ;
   endmethod

   method a_type first () if (cross_fifo.i_notEmpty );
      return cross_fifo.first ;
   endmethod

endmodule

//@ # 5
module mkSyncFIFOToFast #( Integer depth
                          )( ClockDividerIfc divider,
                             Reset slowRstIn,
                             SyncFIFOIfc #(a_type) ifc )
   provisos (Bits#(a_type,sizea)) ;

   FIFOF_MC#(a_type)    cross_fifo() ;
   vFIFOF_MC#( depth )   crossFIFOdst( divider.slowClock, slowRstIn,
                                      divider.fastClock, noReset,
                                      divider.slowClock, slowRstIn,
                                      cross_fifo ) ;

   // Enq is in the slow clock domain, and thus is ready as long as it is not full
   method Bool notFull =  (cross_fifo.i_notFull ) ;

   method Action enq( a_type din ) if (cross_fifo.i_notFull ) ;
      cross_fifo.enq( din ) ;
   endmethod

   // Dequeue can only happen when the slow clock will tick
   method Bool notEmpty =  (cross_fifo.i_notEmpty && divider.clockReady ) ;

   method Action deq() if (cross_fifo.i_notEmpty && divider.clockReady ) ;
      cross_fifo.deq( ) ;
   endmethod

   // The first is always ready if there is an element present
   method a_type first () if (cross_fifo.i_notEmpty );
      return cross_fifo.first ;
   endmethod

endmodule

/////////////////////////////////////////////////////////////////////////
//@ \subsubsection{Reset Generation and Synchronization}
//@ \index{mkReset@\te{mkReset} (module)|textbf}
//@ \index{mkResetSync@\te{mkResetSync} (module)|textbf}
//@ \index{mkSyncReset@\te{mkSyncReset} (module)|textbf}
//@ \index{mkSyncResetFromCR@\te{mkSyncResetFromCR} (module)|textbf}
//@ \index{mkAsyncReset@\te{mkAsyncReset} (module)|textbf}
//@ \index{mkAsyncResetFromCR@\te{mkAsyncResetFromCR} (module)|textbf}
//@ \index{mkInitialReset@\te{mkInitialReset} (module)|textbf}
//@ \index{mkResetMux@\te{mkResetMux} (module)|textbf}
//@ \index{mkResetEither@\te{mkResetEither} (module)|textbf}
//@


// Seen by users of mkReset and mkResetSync
interface MakeResetIfc;
   method Action assertReset();
   method Bool isAsserted();
   interface Reset new_rst;
endinterface

import "BVI" MakeReset =
module vMkReset#( Integer stages, Bool startInRst )
                ( Clock dClkIn, MakeResetIfc ifc ) ;
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   default_reset rst(RST) ;

   parameter RSTDELAY =
       (stages > 0) ? (stages - 1) :
       error("Reset synchronizers must have 1 or more stages") ;
   parameter init = pack(!startInRst);

   method assertReset () enable(ASSERT_IN) ;
   method ASSERT_OUT isAsserted() ;
   schedule isAsserted CF isAsserted;
      schedule isAsserted SB assertReset;
      schedule assertReset C assertReset;

   input_clock dst_clk(DST_CLK, (*unused*)DST_CLK_GATE) = dClkIn ;
   output_reset new_rst(OUT_RST) clocked_by(dst_clk) ;
endmodule

import "BVI" MakeResetA =
module vMkResetA#( Integer stages, Bool startInRst )
                 ( Clock dClkIn, MakeResetIfc ifc ) ;
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   default_reset rst(RST) ;

   parameter RSTDELAY =
       (stages > 0) ? (stages ) :
       error("Reset synchronizers must have 1 or more stages") ;
   parameter init = pack(!startInRst);

   method assertReset () enable(ASSERT_IN) ;
   method ASSERT_OUT isAsserted() ;
   schedule isAsserted CF isAsserted;
   schedule isAsserted SB assertReset;
   schedule assertReset C assertReset;

   input_clock dst_clk(DST_CLK, (*unused*)DST_CLK_GATE) = dClkIn ;
   output_reset new_rst(OUT_RST) clocked_by(dst_clk) ;
endmodule

import "BVI" MakeReset0 =
module vMkReset0 #( Bool startInRst ) ( Clock dClkIn, MakeResetIfc ifc ) ;
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   default_reset rst(RST) ;

   parameter init = pack(! startInRst);

   method assertReset () enable(ASSERT_IN) ;
   method ASSERT_OUT isAsserted() ;
   schedule isAsserted CF isAsserted;
   schedule isAsserted SB assertReset;
   schedule assertReset C assertReset;

   input_clock dst_clk() = dClkIn ;
   output_reset new_rst(OUT_RST) clocked_by(dst_clk) ;
endmodule


// Needed for module BVI, users should not need this
interface ResetGenIfc;
  interface Reset gen_rst;
endinterface

import "BVI" SyncResetA =
module vSyncResetA#( Integer stages ) ( Reset rstIn, ResetGenIfc rstOut ) ;
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   no_reset ;

   // we don't care what the clock is of the input reset
   input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ;

   parameter RSTDELAY = (stages > 0) ? (stages - 1) :
                        error("Reset synchronizers must have 1 or more stages") ;

   output_reset gen_rst(OUT_RST) clocked_by( clk) ;
endmodule

import "BVI" SyncReset =
module vSyncReset#(Integer stages ) ( Reset rstIn, ResetGenIfc rstOut ) ;
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   no_reset ;

   // we don't care what the clock is of the input reset
   input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ;

   parameter RSTDELAY = (stages > 0) ? (stages - 1) :
                        error("Reset synchronizers must have 1 or more stages") ;

   output_reset gen_rst(OUT_RST) clocked_by( clk) ;
endmodule

import "BVI" SyncReset0 =
module vSyncReset0 ( Reset rstIn, ResetGenIfc rstOut ) ;
   default_clock clk();
   no_reset ;

   // we don't care what the clock is of the input reset
   input_reset rst(IN_RST) clocked_by (no_clock) = rstIn ;

   output_reset gen_rst(OUT_RST) clocked_by( clk) ;
   //path ( IN_RST, OUT_RST ) ;
endmodule


import "BVI" InitialReset =
module vInitialReset#(Integer cycles ) ( ResetGenIfc rstOut );
   default_clock clk(CLK, (*unused*)CLK_GATE) ;
   no_reset ;

   parameter RSTHOLD =
       (cycles > 0) ? cycles :
       error("Reset generator built with hold cycles less than 1") ;

   output_reset gen_rst(OUT_RST) clocked_by( clk) ;

endmodule


//@ Reset generation allows the conversion of a Boolean type to a
//@ Reset type, where the reset is associated with the default (or
//@ {\tt clocked\_by}) clock domain.
//@ Two modules provide this function, {\tt  mkReset} and {\tt
//@ mkResetSync}, where each module has one parameter, {\tt stages}.
//@ The {\tt stages}  argument is the number of full clock
//@ cycles the output reset is held after the input reset is
//@ deasserted.  Specifying a 0 for the {\tt stages} argument results
//@ in the creation of a simple wire between the {\tt bRstIn} and {\tt
//@ rstOut}.  That is, the reset is asserted immediately and not held
//@ after the {\tt bRstIn} is deasserted.  It becomes the designer's
//@ responsibility to ensure that {\tt bRstIn} is asserted for
//@ sufficient time to allow the design to reset properly.
//@ Note that the Boolean input {\tt bRstIn} is asserted
//@ low, and can be taken from any clock domain.
//@
//@ The difference between {\tt mkReset} and {\tt mkResetSync}
//@ is that for the former, the assertion of reset is immediate, while
//@ the later asserts reset at the next rising edge of the clock.
//@ Note that the use
//@ mkResetSync is less common, since the reset requires clock edges
//@ to take effect; failure to assert reset for a clock edge will not
//@ result in a reset being seen at {\tt rstOut}.
//@

//@ # 2
module mkReset #( Integer stages,
		  Bool startInRst
                 )( Clock dClkIn,
		    MakeResetIfc ifc ) ;

   (* hide *)
   MakeResetIfc _ifc <- ( stages == 0 ) ?
                        vMkReset0(startInRst, dClkIn) :
                        vMkResetA(stages, startInRst, dClkIn) ;
   return _ifc ;
endmodule

//@ # 2
module mkResetSync #( Integer stages,
		      Bool startInRst
                     )( Clock dClkIn,
		        MakeResetIfc ifc ) ;

   (* hide *)
   MakeResetIfc _ifc <- ( stages == 0 ) ?
                        vMkReset0(startInRst, dClkIn) :
                        vMkReset(stages, startInRst, dClkIn) ;
   return _ifc ;
endmodule


//@ To synchronize resets from one clock domain to another, several
//@ modules are provided. The {\tt mkAsyncReset} family is similar to
//@ the {\tt mkReset} module; the {\tt stages} argument has the same
//@ behavior.
//@ # 4
module mkAsyncReset #( Integer stages
                      )( Reset sRst,
                         Clock dClkIn,
                         Reset dRstOut ) ;

   (* hide *)
   ResetGenIfc _ifc <- ( stages == 0 ) ?
                       vSyncReset0( sRst, clocked_by( dClkIn ) ) :
                       vSyncResetA( stages, sRst,  clocked_by( dClkIn ) ) ;
   return _ifc.gen_rst ;
endmodule

//@ # 3
module mkAsyncResetFromCR #( Integer stages
                            )( Clock dClkIn,
                               Reset dRstOut ) ;
   (* hide *)
   Reset _sRst <- exposeCurrentReset ;
   (* hide *)
   Reset _dRst <- mkAsyncReset(stages, _sRst, dClkIn) ;
   return _dRst ;
endmodule

//@ The less common {\tt mkSyncReset} modules are provided for
//@ convenience, but these modules {\em require} that {\tt sRst} be held
//@ during a positive edge of {\tt dClkIn} for the reset assertion to
//@ be noticed.
//@ # 4
module mkSyncReset #( Integer stages
                     )( Reset sRst,
                        Clock dClkIn,
                        Reset dRstOut ) ;

   let msg = "The use of a mkSyncReset may not always result in a reset" +
           " signal being seen on the destination side." +
           " Recommend replacement with mkAsyncReset";
   (* hide *)
   ResetGenIfc _ifc <- ( stages == 0 ) ?
                       vSyncReset0( sRst, clocked_by( dClkIn ) ) :
                       vSyncReset( stages, sRst,  clocked_by( dClkIn ) )  ;
   return warning ( msg, _ifc.gen_rst ) ;
endmodule

//@ # 3
module mkSyncResetFromCR #( Integer stages
                           )( Clock dClkIn,
                              Reset dRstOut ) ;
   let msg = "The use of a mkSyncResetFromCR may not always result in a reset" +
           " signal being seen on the destination side." +
           " Recommend replacement with mkAsyncResetFromCR";
   (* hide *)
   Reset _sRst <- exposeCurrentReset ;

   // We could use this if we didn't mind the message being the same
   //Reset _dRst <- mkSyncReset(stages, _sRst, dClkIn) ;
   //return _dRst ;
   (* hide *)
   ResetGenIfc _ifc <- ( stages == 0 ) ?
                       vSyncReset0( _sRst, clocked_by( dClkIn ) ) :
                       vSyncReset( stages, _sRst, clocked_by( dClkIn ) )  ;
   return warning ( msg, _ifc.gen_rst ) ;
endmodule


//@ For testbenches, in which an absolute clock is being created,
//@ it is helpful to generate a reset for that clock.
//@ The module {\tt mkInitialReset} generates a reset on the first
//@ clock that it receives.  The reset is asserted for a number of
//@ cycles specified by the parameter, which must be greater than zero.
//@ This module is not consider synthesizable.

//@ # 2
module mkInitialReset #( Integer cycles
                        )( Reset rstOut ) ;
   (*hide*)
   ResetGenIfc _ifc <- vInitialReset(cycles);
   return _ifc.gen_rst ;
endmodule


//@ For selecting between two resets, {\tt mkResetMux} is available.
//@ This module provides protection for the user by requiring that the
//@ resets be associated with the same clock and, further, that the
//@ selector signal is in the same domain.

//@ # 4
interface MuxRstIfc;
   method    Action select ( Bool ab ) ;
   interface Reset  reset_out ;
endinterface

import "BVI" ResetMux =
//@ # 1
module mkResetMux (Reset aRst, Reset bRst, MuxRstIfc ifcout) ;

   default_clock xclk(CLK, (*unused*)CLKGATE) ;
   no_reset;

   input_reset aRst(A_RST) clocked_by(xclk) = aRst ;
   input_reset bRst(B_RST) clocked_by(xclk) = bRst ;

   output_reset reset_out(RST_OUT) clocked_by(xclk) ;

   method select(SELECT) enable(SELECT_ENABLE)
                         clocked_by (xclk)
                         reset_by (no_reset) ;

      schedule select C select ;
endmodule

// used internally only
interface JoinRstIfc;
   interface Reset reset_out;
endinterface

import "BVI" ResetEither =
module vMkResetEither (Reset aRst, Reset bRst, JoinRstIfc ifcout) ;

   default_clock xclk();
   no_reset;

   input_reset aRst(A_RST) clocked_by(xclk) = aRst;
   input_reset bRst(B_RST) clocked_by(xclk) = bRst;

   output_reset reset_out(RST_OUT) clocked_by(xclk);

endmodule

module mkResetEither(Reset aRst, Reset bRst, Reset ifc);
   (* hide *)
   JoinRstIfc _r <- vMkResetEither(aRst,bRst);
   return _r.reset_out;
endmodule

//@ The isResetAsserted module tests whether a Reset is asserted,
//@ yielding a Boolean value in the clock domain associated with
//@ the reset.
module isResetAsserted (ReadOnly#(Bool) ifc );
   Reg#(Bool)  isInReset <- mkRegA(True);
   rule isResetAssertedUpdate (isInReset);
      isInReset <= False;
   endrule
   method Bool _read = isInReset._read;
endmodule

import "BVI" ResetToBool =
module isResetAssertedDirect( ReadOnly#(Bool) ifc ) ;
   default_clock clk() ;
   default_reset rst(RST) ;
   method VAL _read() clocked_by(clk) reset_by(no_reset);
   schedule _read CF _read;
   path (RST,VAL);
endmodule

module mkResetInverter#(Reset in)(Reset);
   let _inv <- vResetInverter(in);
   return _inv.gen_rst;
endmodule

import "BVI" ResetInverter =
module vResetInverter(Reset in, ResetGenIfc out);
   default_clock clk();
   no_reset;

   input_reset  (RESET_IN) clocked_by (no_clock) = in;
   output_reset gen_rst(RESET_OUT) clocked_by (clk);
endmodule

module invertCurrentReset(Reset);
   let in <- exposeCurrentReset;
   let _m <- vResetInverter(in);
   return _m.gen_rst;
endmodule: invertCurrentReset

typeclass ClockConv#(type a);
   module mkConverter#(Integer d, a to_conv)(a);
endtypeclass

instance ClockConv#(ActionValue#(a))
   provisos (Bits#(a,sa));
   module mkConverter#(Integer d)(ActionValue#(a) av, ActionValue#(a) ifc);
      SyncFIFOIfc#(a) ff <- mkSyncFIFOToCC(d, clockOf(av), resetOf(av));
      rule enqueue;
	 let v <- av; ff.enq(v);
      endrule
      let ifc =
        (actionvalue
	    let v =  ff.first;
	    ff.deq;
	    return v;
	 endactionvalue);
      return ifc;
   endmodule
endinstance

instance ClockConv#(function Action af(a x))
   provisos (Bits#(a,sa));
   module mkConverter#(Integer d)(function Action af(a x), function Action af(a x));
      SyncFIFOIfc#(a) ff <- mkSyncFIFOFromCC(d, clockOf(af));
      rule dequeue;
	 af(ff.first);
	 ff.deq;
      endrule
      return (ff.enq);
   endmodule
endinstance

// a sloppy way to make a "disabled clock", with oscillator 0 and gate 1
module primMakeDisabledClockM(Clock);

  (* hide *)
  MakeUngatedClockIfc#(Bit#(1)) _m <- vMkUngatedClock(0);

  return(_m.new_clk);

endmodule

Clock primMakeDisabledClock = primBuildModule(primGetName(disabled_clock), noClock, noReset, primMakeDisabledClockM);
